package com.example.chat.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.chat.domain.dto.LoginFormDTO;
import com.example.chat.domain.dto.RegisterFormDTO;
import com.example.chat.domain.dto.UserDTO;
import com.example.chat.domain.entity.Friendship;
import com.example.chat.domain.entity.User;
import com.example.chat.domain.vo.UserInfoVo;
import com.example.chat.domain.vo.UserStudentIdVo;
import com.example.chat.mapper.UserMapper;
import com.example.chat.result.Result;
import com.example.chat.service.FriendshipService;
import com.example.chat.service.UserInfoService;
import com.example.chat.service.UserService;
import com.example.chat.utils.*;
import com.example.chat.domain.vo.TokenVo;
import com.example.chat.domain.vo.UserVo;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    @Lazy
    private FriendshipService friendshipService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    @Transactional
    public Result register(RegisterFormDTO registerFormDTO) {
        //1.验证手机号格式是否正确
        String phone = registerFormDTO.getPhone();
        if(RegexUtils.isPhoneInvalid(phone)){
            return Result.fail("请输入正确的手机号");
        }
        if("".equals(registerFormDTO.getPassword()) ||
                "".equals(registerFormDTO.getCode()) ||
                "".equals(registerFormDTO.getConfirmPassword())){
            return Result.fail("请输入完整信息");
        }
        //2.判断用户是否存在
        User user = query().eq("phone", registerFormDTO.getPhone()).one();
        if(user != null){
            //4.不存在直接返回
            return Result.fail("已存在，请登录");
        }
        if(!"qwe123".equals(registerFormDTO.getCode())){
            return Result.fail("验证码错误");
        }
        if(!registerFormDTO.getConfirmPassword().equals(registerFormDTO.getPassword())){
            return Result.fail("两次密码不同，请重新输入");
        }
        User user1 = User.builder()
                .phone(registerFormDTO.getPhone())//设置手机号
                .password(DigestUtils.md5DigestAsHex(registerFormDTO.getPassword().getBytes()))//设置密码
                .userName("user_"+ RandomUtil.randomString(10))//设置用户名
                .icon(SystemConstants.USER_DEFAULT_ICON).build();//设置默认头像
        int nowYear = LocalDateTime.now().getYear();
        String formatedStudentId = String.format("%04d", stringRedisTemplate.opsForValue()
                .increment("user:student_id:" + nowYear + ":"));
        Long studentID = Long.valueOf(nowYear + "25" + formatedStudentId);
        user1.setStudentId(studentID);
        boolean save = save(user1);
        if(save){
            return Result.ok(new UserStudentIdVo(studentID));
        }
        return Result.fail("注册失败");
    }

    @Override
    public Result guestLogin(String userName) {
        User user = User.builder()
                .id(Long.MAX_VALUE)
                .userName(userName)
                .icon(SystemConstants.USER_DEFAULT_ICON)
                .build();

        Long userId = user.getId();
            Map<String, Object> claims = new HashMap<>();
            claims.put("user_id",userId);
            String token = JwtUtil.createJWT(claims);
            return Result.ok(new TokenVo(token,userId,user.getUserName(),user.getIcon(),
                    SystemConstants.USER_ROLE_GUEST));
    }

    @Override
    public Result login(LoginFormDTO loginForm) {
        String phone = loginForm.getPhone();
        String password = loginForm.getPassword();
        String studentId = loginForm.getStudentId();
        if((phone == null && studentId != null && studentId.isEmpty()) || studentId == null && phone != null && phone.isEmpty()){
            return Result.fail("请输入数据");
        }
        User one;
        if(phone != null){
            //验证手机号格式是否正确
            if(RegexUtils.isPhoneInvalid(phone)){
                return Result.fail("请输入正确的手机号");
            }
            //判断用户是否存在
            User user = query().eq("phone", loginForm.getPhone()).one();
            if(user == null){
                //不存在直接返回
                return Result.fail("不存在，请先注册");
            }
            one = query().eq("phone", loginForm.getPhone())
                    .eq("password", DigestUtils.md5DigestAsHex(password.getBytes())).one();
            if(one == null){
                return Result.fail("密码错误");
            }
        }else{
            if(studentId.length() != 10){
                return Result.fail("请输入正确的学号");
            }
            User user = query().eq("student_id", studentId).one();
            if(user == null){
                return Result.fail("不存在，请先注册");
            }
            one = query()
                    .eq("student_id", studentId)
                    .eq("password", DigestUtils.md5DigestAsHex(password.getBytes())).one();
            if(one == null){
                return Result.fail("密码错误");
            }
        }
        Map<String, Object> claims = new HashMap<>();
        claims.put("user_id",one.getId());
        String token = JwtUtil.createJWT(claims);
        return Result.ok(new TokenVo(token,one.getId(),one.getUserName(),one.getIcon()
                ,SystemConstants.USER_ROLE_STUDENT));
    }

    @Override
    public Result upload(MultipartFile file) {
        try {
            // 获取原始文件名称
            String originalFilename = file.getOriginalFilename();
            // 生成新文件名
            String fileName = createNewFileName(originalFilename);
            // 保存文件
            file.transferTo(new File(SystemConstants.IMAGE_UPLOAD, fileName));
            String url = "http://192.168.137.1:9090/commons/download?name="+fileName;
            return Result.ok(url);
        } catch (IOException e) {
            throw new RuntimeException("文件上传失败", e);
        }
    }

    @Override
    public Result getMyself() {
        Long currentId = UserHolder.getCurrentId();
        User user = getById(currentId);
        UserVo userVo = new UserVo();
        userVo.setUserName(user.getUserName());
        userVo.setSex(user.getSex());
        userVo.setStudentId(user.getStudentId());
        userVo.setIcon(user.getIcon());
        return Result.ok(userVo);
    }

    @Override
    public Result updateSelf(UserDTO userDTO) {
        Long currentId = UserHolder.getCurrentId();
        userDTO.setId(currentId);
        boolean success = updateById(BeanUtil.copyProperties(userDTO, User.class));
        if(!success){
            return Result.fail("修改失败");
        }
        return Result.ok("修改成功");
    }

    @Override
    public Result updatePwd(String oldPassword, String newPassword, String confirmPassword) {
        Long currentId = UserHolder.getCurrentId();
        if(StrUtil.isEmptyIfStr(oldPassword) ||
                StrUtil.isEmptyIfStr(newPassword) ||
                StrUtil.isEmptyIfStr(confirmPassword)){
            return Result.fail("请输入完整信息");
        }
        User user = getById(currentId);
        String password = user.getPassword();
        String oldPasswordMD5  = DigestUtils.md5DigestAsHex(oldPassword.getBytes());
        if(!password.equals(oldPasswordMD5)){
            return Result.fail("密码错误");
        }
        if(oldPassword.equals(newPassword)){
            return Result.fail("新密码与旧密码相同");
        }
        if(!newPassword.equals(confirmPassword)){
            return Result.fail("两次新密码不一样");
        }
        user.setPassword(DigestUtils.md5DigestAsHex(newPassword.getBytes()));
        boolean update = updateById(user);
        if(!update){
            return Result.fail("修改失败");
        }
        return Result.ok("修改成功");
    }

    @Override
    public Result getUserTypeById(Long id) {
        Long currentId = UserHolder.getCurrentId();
        UserInfoVo userInfoVo = BeanUtil.toBean(getById(id), UserInfoVo.class);
        //设置与该用户type,0用户自己 1陌生人,2.已有请求中,3已是好友关系
        if(id.equals(currentId)){
            //用户自己
            userInfoVo.setType(0);
            return Result.ok(userInfoVo);
        }
        //3.1、判断是否已是好友关系
        Boolean isSuccess = stringRedisTemplate.opsForSet()
                .isMember(RedisConstants.ADDRESSLIST_FRIENDS + id, currentId.toString());
        if(isSuccess){
            userInfoVo.setType(3);
            return Result.ok(userInfoVo);
        }
        //判断是否已有请求
        Long count1 = friendshipService.lambdaQuery()
                .in(Friendship::getSendId, List.of(currentId,id))
                .in(Friendship::getReceiveId, List.of(currentId,id))
                .in(Friendship::getStatus,List.of(0,2)).count();
        if(count1 > 0){
            //与该用户申请好友中,
            userInfoVo.setType(2);
            return Result.ok(userInfoVo);
        }
        //陌生用户
        userInfoVo.setType(1);
        return Result.ok(userInfoVo);
    }

    private String createNewFileName(String originalFilename) {
        // 获取后缀
        String suffix = StrUtil.subAfter(originalFilename, ".", true);
        // 生成目录
        String name = UUID.randomUUID().toString();
        int hash = name.hashCode();
        int d1 = hash & 0xF;
        int d2 = (hash >> 4) & 0xF;
        // 判断目录是否存在
        File dir = new File(SystemConstants.IMAGE_UPLOAD_DIR);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        // 生成文件名
        return StrUtil.format("{}.{}",name, suffix);
    }
}
